package net.oschina.allchat.message.processing.conversion.converters;

import net.oschina.allchat.message.processing.conversion.ConversionException;
import net.oschina.allchat.message.processing.conversion.IConverter;
import net.oschina.allchat.message.processing.conversion.IConverterFactory;
import net.oschina.allchat.message.processing.conversion.converters.annotations.StringToEnum;

public class StringToEnumConverterFactory implements IConverterFactory<StringToEnum> {
	
	@Override
	public IConverter create(StringToEnum stringToEnum) {
		return new StringToEnumConverter(stringToEnum.type(), stringToEnum.upperCaseString(),
				stringToEnum.dashToUnderline());
	}
	
	private class StringToEnumConverter implements IConverter {
		private Class<?> type;
		private boolean upperCase;
		private boolean dashToUnderline;
		
		public StringToEnumConverter(Class<?> type, boolean upperCase, boolean dashToUnderline) {
			this.type = type;
			this.upperCase = upperCase;
			this.dashToUnderline = dashToUnderline;
		}
		
		@Override
		public Object from(Object obj) throws ConversionException {
			if (type == null) {
				throw new RuntimeException("StringToEnumConverter needs 'type' argument");
			}
				
			if (!(obj instanceof String)) {
				throw new ConversionException(String.format("StringToEnumConverter needs a string, not a %s", obj.getClass().getName()));
			}
			
			String string = (String)obj;
			String enumString = convertToEnumString(string);
			
			Object[] objects = type.getEnumConstants();
			for (Object object : objects) {
				if (object.toString().equals(enumString))
					return object;
			}
			
			throw new ConversionException(String.format("can't convert %s to enum %s", string, type.getName()));
		}

		private String convertToEnumString(String string) {
			String enumString = new String(string);
			if (upperCase) {
				enumString = enumString.toUpperCase();
			}
			
			if (dashToUnderline) {
				enumString = enumString.replace('-', '_');
			}
			
			return enumString;
		}

		@Override
		public String to(Object obj) throws ConversionException {
			if (!obj.getClass().isEnum()) {
				throw new ConversionException(String.format("need a enum, but is %s", obj.getClass()));
			}
			
			for (Object enumConstant : obj.getClass().getEnumConstants()) {
				String enumString = enumConstant.toString();
				if (!enumString.equals(obj.toString()))
					continue;
				
				if (upperCase) {
					enumString = enumString.toLowerCase();
				}
				
				if (dashToUnderline) {
					enumString = enumString.replace('_', '-');
				}
				
				return enumString;
			}
			
			throw new ConversionException("can't convert enum to string!!!???");
		}
		
	}
	
}
